home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / blockio-c.txt < prev    next >
Encoding:
Internet Message Format  |  1994-11-23  |  15.9 KB  |  [TEXT/unix]

  1. From: "Art Eschenlauer" <eschen@molbio.cbs.umn.edu>
  2. Subject: Routines that open blocks as filestreams in ThC 5
  3. Date: Sat, 24 Sep 1994 12:31:39 -0500 (CDT)
  4.  
  5. Here's a file to put into /mac/development/sources/snippets on
  6. mac.archive.umich.edu. Compress it as you please.
  7.  
  8.  
  9. /*
  10. blockio.c and blockio.h by Art Eschenlauer
  11.  
  12. Routines to open blocks of memory as simple filestreams under ThinkC 5.0.4
  13.  
  14. Here are some routines to open a block of memory (Ptr or Handle) as a simple
  15. filestream (they do not support disk oriented commands like rewind and seek).
  16. I wrote these for porting unix software to ThinkC 5.0.4 using the standard 
  17. libraries. I don't know if they would work on later versions of ThinkC std
  18. libraries. Bugs, comments, flames, etc. to eschen@molbio.cbs.umn.edu.
  19.  
  20. Disclaimer:
  21.  
  22. ++++++++++   NOTICE - GRATIS EXPERIMENTAL SOFTWARE   ++++++++++
  23.  
  24. THIS IS EXPERIMENTAL SOFTWARE THAT IS PROVIDED "AS IS" FOR YOUR USE, GRATIS. NO
  25. WARRANTY OR REPRESENTATION WHATSOEVER, EITHER EXPRESS OR IMPLIED, IS GIVEN WITH
  26. RESPECT TO THIS SOFTWARE, ITS QUALITY, PERFORMANCE, MERCHANTABILITY, OR FITNESS
  27. FOR A PARTICULAR PURPOSE. IF YOU CHOOSE TO USE IT, YOU ASSUME ALL RISKS AS TO
  28. ITS QUALITY AND PERFORMANCE, INCLUDING (BUT NOT LIMITED TO) LOST TIME, DATA,
  29. MONEY, AND USE OF, OR DAMAGE TO, YOUR COMPUTER, YOUR BRAIN, ETC.. NO ONE SHALL
  30. IN ANY EVENT BE HELD LIABLE  FOR ANY DAMAGE OR LOSS THAT MAY BE CAUSED BY, OR
  31. MAY BE ASSOCIATED WITH, THIS SOFTWARE.
  32.  
  33. Translation: you didn't pay (or shouldn't have paid) for this EXPERIMENTAL
  34. software, so it's up to you to cover any damages. While I have tested this
  35. software (somewhat) and have no malicious intent in providing this software,
  36. excrement transpires, and it's up to you to wipe it up. YOU MAY NOT USE THIS
  37. SOFTWARE IF YOU DO NOT AGREE WITH THE ABOVE.
  38.  */
  39. /*-snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip-*/
  40. /*
  41. * blockio.h - filestream i/o for pointers to memory blocks
  42. * Interface to public routines defined in blockio.c
  43. *
  44. * ThinkC 5.0.4, 7 June 1994
  45. * notcopyright (!)) 1994 Art Eschenlauer - PUBLIC DOMAIN!!!!
  46. *
  47. * These routines are to support filestream i/o operations 
  48. * to pointers, in the same manner that 
  49. * <console.c> supports filestream io to the console interface and 
  50. * <fopen.c> supports filestream io to macintosh files and 
  51. * <stdio.c> supports filestream io to c-strings
  52. *
  53. * These routines require that blocks be allocated as Ptr's or Handle's
  54. * (excepting for freopenblock).
  55. *
  56. * I suggest that you may want to close output streams like so
  57. *   fputc(0,theBlockStream); fclose(theBlockStream);.
  58. * Caveat emptor!!
  59. */
  60. #ifndef __BLOCKSTREAM__
  61. #define __BLOCKSTREAM__ 1
  62.  
  63. #include <stdio.h>
  64.  
  65. //// Routines for dealing with Ptr's ////
  66. // (For Handle's, see below)
  67.  
  68. // fopenPtr - open a (nonrelocatable) block of memory as a filestream
  69. //    theBlockPtr is a Ptr to the block of memory
  70. //    mode is "r", "w", "rb", or "wb"
  71. //    (Nonrelocatable blocks cannot be opened in append mode.)
  72.  
  73. FILE *
  74. fopenPtr( const Ptr theBlockPtr, const char *mode );
  75.  
  76. // freopenPtr - open a (nonrelocatable) block of memory as a filestream
  77. //    using the file table pointed by fp.
  78. //    theBlockPtr is a Ptr to the block of memory
  79. //    mode is "r", "w", "rb", or "wb"
  80. //    (Don't reopen stdin as "w" or "a" or reopen stdout or stderr as "r"!)
  81.  
  82. FILE *
  83. freopenPtr( const Ptr theBlock, const char *mode, FILE *fp );
  84.  
  85.  
  86. //// Routine for dealing with block of memory not allocated as Ptr ////
  87.  
  88. // freopenblock - open a (nonrelocatable) block of memory as a filestream
  89. //    using the file table pointed by fp.
  90. //    theBlock is a Ptr to the block of memory
  91. //    mode is "r", "w", "rb", or "wb"
  92. //    NEVER use theBlockSize < 0 or theBlockSizeIncrement != 0, and be sure
  93. //    that fp, theBlock, and mode are valid
  94. FILE *
  95. freopenblock( const char *theBlock, const char *mode, Size theBlockSize,
  96.    Size theBlockSizeIncrement, FILE *fp );
  97.    
  98.  
  99. //// Routines for dealing with Handle's ////
  100.  
  101. /*
  102. * Note Well:
  103. *
  104. * Do not unlock relocatable blocks till after the filestream is closed!! 
  105. * Do NOT assume that they do not relocate while the filestream is open!!
  106. * Only relocatable blocks (Handles) can be expanded as need be.
  107. * theBlockSizeIncrement (which specifies how much to grow the block
  108. * each time) must be nonzero for expansion of relocatable blocks;
  109. * use zero for theBlockSizeIncrement if using modes "r" or "w".
  110. */
  111.  
  112. // fopenHandle - open a relocatable block of memory as a filestream
  113. //    theBlockHandle is a Handle to the block of memory
  114. //    mode is "r", "w", or "a"
  115. //    (Only relocatable blocks can be opened in append mode.)
  116.  
  117. FILE *
  118. fopenHandle( const Handle theHandle, const char *mode, 
  119.   Size theBlockSizeIncrement );
  120.  
  121. // freopenHandle - open a block of memory as a filestream
  122. //    using the file table pointed by fp.
  123. //    theBlockPtr is a pointer to the block of memory
  124. //    mode is "r", "w", "a", "rb", "wb", "ab"
  125. //    (Don't reopen stdin as "w" or "a" or reopen stdout or stderr as "r"!)
  126.  
  127. FILE *
  128. freopenHandle( const Handle theHandle, const char *mode, 
  129.   Size theBlockSizeIncrement, FILE *fp );
  130.   
  131. #endif __BLOCKSTREAM__
  132. /*-snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip-*/
  133.  
  134.  
  135. /*
  136. * blockio.c - filestream i/o for pointers to memory blocks
  137. * notcopyright (!)) 1994 Art Eschenlauer - PUBLIC DOMAIN!!!!
  138. * see "blockio.h" for usage info
  139. * ThinkC 5.0.4, 6 June 1994
  140. *
  141. * To link successfully, projects using blockio.c must include the oops library.
  142. */
  143.  
  144. // stdio.h defines BUFSIZE and _IOFBF
  145. #include <stdio.h>
  146. #include <ansi_private.h>
  147. #include <errno.h>
  148. #include <string.h>
  149.  
  150. // convenience includes
  151. //#include <Memory.h>
  152. // typedef long Size        (see Memory.h)
  153. // typedef unsigned long size_t   (see size_t.h)
  154.  
  155.  
  156. /// PRIVATE ROUTINE PROTOTYPES AND CLASS DECLARATION ///
  157.  
  158. // i/o routine that is assigned to fp->proc
  159. static int
  160. blockio( FILE *fp, int i );
  161.  
  162. // setupblockfp actually does the work of setting up the file
  163. //    table entry so that an entry can use a block of
  164. //    memory, pointed by theBlockPtr and of size theBlockSize,
  165. //    as the input filestream or output filestream:
  166.  
  167. static FILE *
  168. setupblockfp( FILE *fp, const char *s, Size theBlockSize,
  169.               Size theBlockSizeIncrement, Boolean  _APPENDMODE );
  170.  
  171. // Cblock class - I do not intend other functions to use the Cblock class
  172. //   I really only used it to dynamically allocate a structure that can be
  173. //   referenced using fp->long in the file table. If you want to use it in other
  174. //   functions, remove it from blockio.c and put it in blockio.h
  175.  
  176. class Cblock : direct {
  177. public:
  178.  
  179. /// Instance variables ///
  180.   
  181.   char  *start;   // first byte in block
  182.   char  *pos;   // current position to read/write in block of memory
  183.   char  *end;   // last byte in block
  184.   Size  increment;  // size by which block is to expand if space runs out
  185.             //   (nonzero only if block is Handle opened for append)
  186.   Handle  hblock;   // handle to block if block is relocatable
  187.   char  hstate;   // state of handle (locked etc.) before opening block stream
  188.  
  189. /// Methods ///
  190.   
  191.   //  initialize Cblock object, true if succeeds
  192.   Boolean Iblock( const char *s, Size theBlockSize, 
  193.         Size theBlockSizeIncrement, Boolean _APPENDMODE );
  194.  
  195.   // destruct Cblock object
  196.   void Dblock(void);
  197.  
  198. };
  199.  
  200.  
  201. /// PUBLIC ROUTINE PROTOTYPES ///
  202. #ifndef __BLOCKSTREAM__
  203. #include "blockio.h"
  204. #endif __BLOCKSTREAM__
  205.  
  206.  
  207. /// PRIVATE ROUTINE DEFINITIONS ///
  208.  
  209. /* blockio - I/O proc installed into FILE structure, so that __read,
  210. *        __write, and __close will all work with the block of memory
  211. *       (see bufio.c).
  212. *
  213. *       this is set up to point to the block associated with the fp
  214. */
  215. static int
  216. blockio(FILE *fp, int i)
  217. {
  218.   int result;
  219.   register  Cblock *this;
  220.   register  int counter;
  221.   
  222.   // recover reference to the object associated with the filepointer
  223.   this = (Cblock *) fp->window;
  224.   
  225.   result = 0;
  226.   switch(i)
  227.   {
  228.     case 0: //read
  229.         
  230.     //handle EOF case
  231.     if (this->pos >= this->end)
  232.       { fp->cnt = 0; fp->eof = 1; return EOF; }
  233.     //determine # bytes to read
  234.     counter = fp->cnt = (fp->size > (this->end - this->pos))  ?
  235.       this->end - this->pos  :  fp->size;
  236.     //transfer bytes to buffer
  237.     while (counter--) 
  238.       *(fp->ptr++) = *(this->pos++);
  239.     //reset fp->ptr
  240.     fp->ptr = (unsigned char *) fp->buf;
  241.     fp->eof = 0;
  242.  
  243.     if (!fp->binary)
  244.     {
  245.       #pragma options(honor_register)
  246.       register unsigned char *s;
  247.       register size_t n;
  248.       register unsigned char *t;
  249.       n = fp->cnt;
  250.       s = (unsigned char *) fp->buf;
  251.       for (; n && (t = memchr(s, '\r', n)); s = t) 
  252.       {
  253.         *t++ = '\n';
  254.         n -= t - s;
  255.       }
  256.     }
  257.  
  258.     break; //(switch)
  259.  
  260.     case 1: //write
  261.     
  262.     // tryagain loop begins here
  263. tryagain:
  264.       if ((counter = fp->cnt) > (this->end - this->pos)) 
  265.       {
  266.         if( this->increment )
  267.         { // attempt to expand Handle size
  268.           // and, if successful, try output again
  269.           
  270.           Size oldHandleSize;
  271.           
  272.           HUnlock( this->hblock );
  273.           SetHandleSize(  this->hblock,  this->increment 
  274.             + ( oldHandleSize = GetHandleSize( this->hblock ) )  );
  275.           HLock( this->hblock );
  276.           
  277.           if (oldHandleSize == GetHandleSize( this->hblock ))
  278.           
  279.             goto bail; // break from tryagain loop
  280.           
  281.           // (else)
  282.             this->end += ( *this->hblock - this->start );
  283.             this->pos += ( *this->hblock - this->start );
  284.             this->start = *this->hblock;
  285.             fp->len += this->increment;
  286.             this->end += this->increment;
  287.             
  288.             goto tryagain; // loop back to tryagain
  289.             
  290.     // tryagain loop ends here
  291.         }
  292.  
  293. bail:
  294.           // write all you can, and
  295.         //  update result, counter, fp->cnt, fp->eof, and fp->pos 
  296.         //  to reflect end of file condition
  297.         
  298.         result = EOF;
  299.         fp->pos -= fp->cnt -= (counter = this->end - this->pos);
  300.         fp->eof = 1;
  301.       }
  302.       else 
  303.         // fp->cnt <= (this->end - this->pos)
  304.         fp->cnt = 0;
  305.  
  306.  
  307.     // counter (set at tryagain) holds number of bytes to transfer 
  308.     //   from buffer to block
  309.  
  310.     if (!fp->binary)
  311.     {
  312.       #pragma options(honor_register)
  313.       register unsigned char *s;
  314.       register size_t n;
  315.       register unsigned char *t;
  316.       n = counter;
  317.       s = (unsigned char *) fp->buf;
  318.       for (; n && (t = memchr(s, '\n', n)); s = t) 
  319.       {
  320.         *t++ = '\r';
  321.         n -= t - s;
  322.       }
  323.     }
  324.  
  325.     while (counter--)
  326.       *(this->pos++) = *(fp->ptr++);
  327.     break; // (switch)
  328.  
  329.     case 2: //close
  330.  
  331.     //close filestream and delete object
  332.     memset(fp,0,sizeof(FILE));
  333.     __checkfile(fp);
  334.     this->Dblock();
  335.   }
  336. bye:
  337.   return result; 
  338. }
  339.  
  340. static FILE *
  341. setupblockfp( FILE *fp, const char *s, Size theBlockSize,
  342.   Size theBlockSizeIncrement, Boolean  _APPENDMODE )
  343. { /*
  344.     setupblockfp creates and initializes the block data structure and the
  345.     corresponding file structure. Actually, initialization of the block
  346.     datastructure is delegated to the Iblock method, and setting up of the
  347.     fp itself is handled by setupblockfp itself.
  348.   */
  349.   Cblock *Oblock;
  350.   
  351.   //create and initialize Oblock object 
  352.   //  that will implement io for block
  353.   Oblock = new Cblock;
  354.   if ( Oblock != NULL )
  355.   { 
  356.     if ( Oblock->Iblock( s, theBlockSize, theBlockSizeIncrement, _APPENDMODE ) )
  357.     { 
  358.       /// set up fp ///
  359.       // set every fp->thing to zero
  360.       memset(fp, 0, sizeof(FILE));
  361.     
  362.       fp->len = ( theBlockSize > 0 )  ?  theBlockSize  :  - theBlockSize ;
  363.     
  364.       /* __checkfile sets
  365.           fp->ptr = fp->buf = &fp->one, fp->size = 1, fp->proc = nullio 
  366.       */ 
  367.       __checkfile(fp); 
  368.         
  369.       //fp->refnum for a disk file >0, for an open stream !=0
  370.       fp->refnum = -1;
  371.         
  372.       //vectored routine (io proc) for block i/o
  373.       fp->proc = blockio;
  374.     
  375.       // store object reference in fp->window
  376.       //    so that the blockio proc can recover it
  377.       fp->window = (void *) Oblock; 
  378.       
  379.       return fp;
  380.  
  381.     }
  382.     Oblock->Dblock();
  383.   }
  384.   return NULL;
  385. }
  386.  
  387. /* 
  388.   Cblock::Iblock - set up instance variables for block i/o:
  389.   Meanings of arguments:
  390.     blocksize < 1: handle size-expansion is possible
  391.     theBlockSizeIncrement > 0: handle size-expansion is requested
  392.     _APPENDMODE == 1: start writing at the end of block instead of beginning
  393.  */
  394. Boolean
  395. Cblock::Iblock(const char *s, Size theBlockSize, 
  396.         Size theBlockSizeIncrement, Boolean _APPENDMODE )
  397. {
  398.  
  399.   if (theBlockSize > 0) 
  400.   {
  401.     this->hblock = NULL;
  402.     this->start  = (char *) s;
  403.   }
  404.   else
  405.   {
  406.     this->hblock = (Handle) s;
  407.     this->hstate = HGetState( this->hblock );
  408.     HLock( this->hblock );
  409.     this->start  = (char *) *( this->hblock );
  410.   }
  411.   
  412.   this->end = 
  413.     ( 
  414.       this->start  + 
  415.         (  ( this->hblock )  ?  - theBlockSize  :  theBlockSize  )
  416.     );
  417.  
  418.   this->pos =  _APPENDMODE  ?  this->end  :  this->start  ;
  419.   
  420.   // only handles can be resized because only handles can be relocated
  421.   this->increment =  theBlockSizeIncrement;
  422.   
  423.   return true;
  424. }
  425.  
  426. /* Cblock::Dblock - destruct Cblock object */
  427. void
  428. Cblock::Dblock()
  429. {
  430.   // restore state to what it was before the Cblock->Iblock call
  431.   if( this->hblock )
  432.     HSetState( this->hblock, this->hstate );
  433.     
  434.   delete this;   // self destruct
  435. }
  436.  
  437.  
  438. /// PUBLIC ROUTINE DEFINITIONS ///
  439.  
  440. FILE *
  441. freopenblock( const char *theBlock, const char *mode, Size theBlockSize,
  442.    Size theBlockSizeIncrement, FILE *fp ) {
  443.  
  444.   // if freopenblock fails, *fp is closed nevertheless...
  445.   
  446.   //be sure it is clear what to work with
  447.   if (fp==NULL) goto fail2;
  448.     
  449.   //do not open console if you do not have to
  450.   fp->std = 0;
  451.   fclose(__checkfile(fp));
  452.   
  453.   /*  interpret "rwa"  */
  454.   // not yet set up for update editing...
  455.   
  456.   switch ( mode[0] )
  457.   {
  458.     case 'r':
  459.     case 'R':
  460.     case 'w':
  461.     case 'W':
  462.     
  463.     // r & w require nonzero length blocks and zero expansion increment, 
  464.     //    respectively
  465.       if ( (0 == theBlockSize) || (0 != theBlockSizeIncrement) ) goto fail;
  466.     
  467.     setupblockfp( fp, theBlock, theBlockSize, 0, false );
  468.     break;  // switch
  469.  
  470.     case 'a':
  471.     case 'A':
  472.  
  473.     // append requires handles and nonzero expansion increment, respectively
  474.       if (  (theBlockSize > 0)  ||  (0 == theBlockSizeIncrement)  ) goto fail;
  475.     
  476.       if ( setupblockfp( fp, ( char *) theBlock, theBlockSize, 
  477.                       theBlockSizeIncrement, true ) )
  478.       {
  479.         // the only good way out of here
  480.         fp->append = 1;
  481.         fp->pos = fp->len;
  482.         break;  // switch
  483.       }
  484.       // dribble through into default (like my financial planning ... ?)
  485.             
  486.     default:
  487.     
  488.       goto fail;
  489.   }
  490.  
  491.   // the only way to this point is through the break switches 
  492.   //    at the end of "rwa" cases
  493.   /*  interpret "b"  */
  494.   switch( mode[1] ) // this will not even matter if strlen(mode)==1
  495.   {
  496.   case 'b':
  497.   case 'B':
  498.     fp->binary = 1;
  499.   }
  500.   
  501.   setvbuf(fp, NULL, _IOFBF, BUFSIZ);
  502.   return fp;
  503.  
  504. fail:
  505.  
  506.   // clean up the fp (if necessary) and return error info
  507.   memset( fp, 0, sizeof(FILE) );
  508.   
  509. fail2:
  510.  
  511.   errno = EINVAL;
  512.   return NULL;
  513. }
  514.  
  515. FILE *
  516. fopenPtr( const Ptr theBlock, const char *mode )
  517. {
  518.  
  519.   return
  520.     freopenPtr( theBlock, mode, __getfile() );
  521.  
  522. }
  523.  
  524. FILE *
  525. freopenPtr( const Ptr theBlock, const char *mode, FILE *fp )
  526.   Size theBlockSize;
  527.   
  528.   theBlockSize = GetPtrSize(theBlock);
  529.   if ( theBlockSize < 1 ) return(NULL); // reject errors & zero length pointers
  530.  
  531.   return 
  532.     freopenblock( (char *) theBlock, mode, theBlockSize, 0, fp );
  533. }
  534.  
  535. FILE *
  536. fopenHandle( const Handle theHandle, const char *mode,
  537.   Size theBlockSizeIncrement )
  538. {
  539.  
  540.   return 
  541.     freopenHandle( theHandle, mode, theBlockSizeIncrement, __getfile() );
  542.  
  543. }
  544.  
  545. FILE *
  546. freopenHandle( const Handle theHandle, const char *mode, 
  547.           Size theBlockSizeIncrement, FILE *fp )
  548. {
  549.  
  550.   Size theHandleSize;
  551.   
  552.   theHandleSize = GetHandleSize(theHandle);
  553.   if ( theHandleSize < 0 ) 
  554.   {
  555.     return(NULL);
  556.   }
  557.   
  558.   return
  559.     freopenblock( (char *) theHandle, mode, 
  560.                  - theHandleSize, theBlockSizeIncrement, fp );
  561.     // Cblock->Iblock is responsible for using nonpositive theHandleSize 
  562.     //   to determine that theHandle is in fact char **, not char *
  563.  
  564.  
  565. }
  566.  
  567. /*-snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip- -snip-*/
  568.  
  569.